package com.xbongbong.pro.message.thread;

import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.message.feign.SalesReportFeignClient;
import com.xbongbong.pro.message.pojo.dto.MessageSaveAllTargetDataDTO;
import com.xbongbong.pro.statistic.result.pojo.SalesReportPojo;
import com.xbongbong.pro.statistic.result.pojo.vo.SalesReportVO;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.toolbox.help.BasicHelper;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.TargetLogEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.TargetLogModel;
import com.xbongbong.sys.model.UserModel;
import feign.RetryableException;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

/**
 * @author zcp
 * @version v1.0
 * @date 2019/4/15 10:20
 * @since v1.0
 */
@Setter
@Getter
public class ReportTargetDataThread extends Thread {
    private static final Logger LOG = LoggerFactory.getLogger(ReportTargetDataThread.class);

    protected SalesReportFeignClient salesReportFeignClient;
    protected CompanyModel companyModel;
    protected UserModel userModel;
    protected CustomerModel customerModel;
    protected TargetLogModel targetLogModel;
    protected CompanyConfigModel companyConfigModel;

    private Integer start;
    private Integer pageSize;
    private List<CompanyEntity> companys;
    private boolean repeatFlag = false;
    private MessageSaveAllTargetDataDTO messageSaveAllTargetDataDTO;

    public ReportTargetDataThread() {
        companys = new ArrayList<>();
    }

    public ReportTargetDataThread(MessageSaveAllTargetDataDTO messageSaveAllTargetDataDTO, List<CompanyEntity> companys, boolean repeatFlag) {
        this.messageSaveAllTargetDataDTO = messageSaveAllTargetDataDTO;
        this.companys = companys;
        this.repeatFlag = repeatFlag;
    }

    public ReportTargetDataThread(MessageSaveAllTargetDataDTO messageSaveAllTargetDataDTO, Integer start , Integer pageSize) {
        this.messageSaveAllTargetDataDTO = messageSaveAllTargetDataDTO;
        this.start = start;
        this.pageSize = pageSize;
    }

    @Override
    public void run() {
        /**
          注，计算指标一般都是在凌晨对上一天的数据进行统计，固对于统计日（或周）的开始截至时间即上一天的开始截止
          （1）正常情况，当天早上统计昨日数据，时间范围：dayStart--dayEnd				同时统计dayEnd-86400所在月份的数据
          （2）今日是周一的时候，统计上一周的数据，时间范围：weekStart--weekEnd			同时统计weekEnd-96400所在月份的数据
         */
        Integer timeType = BasicHelper.getTimeType(DateUtil.getInt());
        Map<String, Integer> ret = BasicHelper.getDayStartAndEnd4Report(timeType);
        Integer dayStartTime = ret.get("start");
        Integer dayEndTime = ret.get("end");
        Integer span = 86400;
        Integer monthStartTime = DateUtil.getFirstDateOfMonthInSomeday(dayEndTime - span);
        Integer monthEndTime = DateUtil.getLastDateOfMonthInSomeday(dayEndTime - span);

        LOG.info("------start calculation company's data------");
        long start = DateUtil.getInt();
        int count = dealwithCompany(monthStartTime.longValue(), monthEndTime.longValue(), dayStartTime.longValue(), dayEndTime.longValue());
        long end = DateUtil.getInt() - start;
        LOG.info("------data save completed, total " + count + " companys, and use " + end + " s------");
        LOG.info("简报数据入库执行完毕，共计算了" + count + "家公司的数据，执行了"+ end/60 +"分钟");
    }

    /**
     * 处理公司数据，分两种情况：
     * （1）处理部分（单个）公司，即this.companys在controller层赋值
     * （2）处理所有公司，即this.companys通过查库获取（所有符合推送条的公司）
     *
     * @param monthStartTime 统计月开始时间
     * @param monthEndTime 统计月结束时间
     * @param dayStartTime 统计日/周开始时间
     * @param dayEndTime 统计日/周结束时间
     * @return 处理了多少的公司
     * @since v3.19
     * @version pro
     * @author cp.zhang
     * @data 2018-3-28 上午11:25:25
     * @update 2019-4-15 从saas移入，并处理成pro调用方式 by zcp
     */
    private int dealwithCompany(Long monthStartTime, Long monthEndTime, Long dayStartTime, Long dayEndTime) {
        Integer pageNum = 100;
        //标记执行了多少家公司
        int count = 0;
        if (this.companys != null && this.companys.size() > 0) {
            LOG.info("------one company's data------");
            for(CompanyEntity company : this.companys){
                //存在客户的才进入计算,先根据corpid计算客户数
                Map<String,Object> param = new HashMap<>(2);
                param.put("corpid", company.getCorpid());
                param.put("del", 0);
                int customerCount = customerModel.getEntitysCount(param);
                if(customerCount > 2 ){
                    //存在客户，客户数小于2的不推送
                    LOG.info("开始计算：公司" + company.getCorpid() + "的简报数据");
                    count ++;
                    try {
                        saveCompanyTargetDate(company, monthStartTime, monthEndTime, dayStartTime, dayEndTime);
                    } catch (Exception e) {
                        LOG.error("公司"+ company.getCorpName() +"("+ company.getCorpid() +")生成简报日志数据出错：", e);
                    }
                }
            }
        }else {
            Map<String,Object> param = new HashMap<>(8);
            param.put("del", 0);
            //企业授权状态 -1：解除授权 0：禁用 1：正常 2：待激活
            param.put("status", 1);
            //是否接受推送消息,1推送，0不推送
            param.put("isPushMessage", 1);
            //来源，1:钉钉 2:独立版
//            param.put("source", 1);
            param.put("orderByStr", "corpid desc");
            Integer end = this.start + this.pageSize;
            List<CompanyEntity> companyList;
            for(;this.start<=end;this.start=this.start+pageNum){
                param.put("start", this.start);
                param.put("pageNum", pageNum);
                companyList = companyModel.findEntitys(param);
                if (companyList == null || companyList.size() == 0) {
                    break;
                }
                int perCount = 0;
                for(CompanyEntity company : companyList){
                    //存在客户的才进入计算,先根据corpid计算客户数
                    Map<String, Object> params = new HashMap<>(8);
                    params.put("corpid", company.getCorpid());
                    params.put("del", 0);
                    int customerCount = customerModel.getEntitysCount(params);
                    if(customerCount > 2 ){
                        //存在客户，客户数小于2的不推送
                        LOG.info("开始计算：公司" + company.getCorpid() + "的简报数据");
                        perCount ++;
                        try {
                            saveCompanyTargetDate(company, monthStartTime, monthEndTime, dayStartTime, dayEndTime);
                        } catch (XbbException e) {
                            LOG.error("公司"+ company.getCorpName() +"("+ company.getCorpid() +")生成简报日志数据出错：", e);
                        }
                    }
                }
                count += perCount;
            }
        }
        return count;
    }

    /**
     * 保存公司的简报指标信息
     *
     * @param company 公司
     * @param monthStartTime 统计月开始时间
     * @param monthEndTime 统计月结束时间
     * @param dayStartTime 统计日/周开始时间
     * @param dayEndTime 统计日/周结束时间
     * @throws XbbException
     * @since saas
     * @version pro
     * @author cp.zhang
     * @data 2017-8-10 下午7:59:19
     * @update 2018-3-28下午 by zcp 对需要排重公司，增加排重逻辑，防止重复刷时公司员工数据重复
     * @update 2019-4-15 从saas移入，并处理成pro调用方式 by zcp
     */
    private void saveCompanyTargetDate(CompanyEntity company, Long monthStartTime, Long monthEndTime, Long dayStartTime, Long dayEndTime) throws XbbException {
        String corpid = company.getCorpid();
        //查出该公司所有可推送的员工
        Map<String,Object> param = new HashMap<>(5);
        param.put("corpid", corpid);
        param.put("del", 0);
        //不接受推送消息，则无需对其进行统计
        param.put("isPushMessage", 1);
        //一页500
        Integer pagerNum = 100;
        Integer userCount = userModel.getEntitysCount(param);
        //总页数
        Integer pageTotal = userCount / pagerNum;
        //不能整除，页码加1
        if (userCount % pagerNum > 0) {
            pageTotal = pageTotal + 1;
        }

        for(int page = 1 ; page < pageTotal + 1 ; page++){
            Integer start = (page - 1) * pagerNum;
            param.put("start", start);
            param.put("pageNum", pagerNum);
            List<UserEntity> users = userModel.findEntitys(param);
            if (users == null || users.size() == 0) {
                //公司无员工
                continue;
            }
            //userId--对应的log实体
            Map<String, TargetLogEntity> uidTargetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (repeatFlag) {
                //如果需要排重，则对公司员工进行排重（一般都是刷单公司数据时，需要排重--防止公司员工数据重复）
                Set<String> userIdIn = new HashSet<String>();
                userIdIn.add("-1");
                for(UserEntity userEntity : users){
                    //遍历公司所有人
                    userIdIn.add(userEntity.getUserId());
                }
                //排重处理--查询该员工当天是否已经有过入库消息
                Map<String, Object> logMap = new HashMap<>(5);
                logMap.put("corpid", corpid);
                logMap.put("userIdIn", userIdIn);
                logMap.put("del", 0);
                logMap.put("startTime", dayStartTime);
                logMap.put("endTime", dayEndTime);
                List<TargetLogEntity> logList = targetLogModel.findEntitys(logMap);
                for (TargetLogEntity targetLogEntity : logList) {
                    uidTargetMap.put(targetLogEntity.getUserId(), targetLogEntity);
                }
            }

            SalesReportPojo salesReportPojo = new SalesReportPojo();
            //调用统计接口时需要用到的登录验证（userId在员工循环内部置入）
            salesReportPojo.setCorpid(corpid);
            salesReportPojo.setPlatform(PlatFormEnum.WEB.getValue());
            //其他参数置入
            salesReportPojo.setUidTargetMap(uidTargetMap);
            salesReportPojo.setMonthStartTime(monthStartTime.intValue());
            salesReportPojo.setMonthEndTime(monthEndTime.intValue());
            salesReportPojo.setDayStartTime(dayStartTime.intValue());
            salesReportPojo.setDayEndTime(dayEndTime.intValue());
            //遍历公司所有人
            for(UserEntity userEntity : users){
                salesReportPojo.setLogUserEntity(userEntity);
                salesReportPojo.setUserId(userEntity.getUserId());
                try {
                    Locale locale = LocaleContextHolder.getLocale();
                    String lang = locale.toString();
                    XbbResponse<SalesReportVO> initVOXbbResp = salesReportFeignClient.chartResultSalesReport(salesReportPojo, lang);
                } catch (RetryableException e){
                    LOG.info("超时异常RetryableException，员工“" + userEntity.getName() + "(userId：" + userEntity.getUserId() + ")”简报数据生成中, corpid=" + corpid);
                } catch (RuntimeException e){
                    LOG.info("超时异常RetryableException，员工“" + userEntity.getName() + "(userId：" + userEntity.getUserId() + ")”简报数据生成中, corpid=" + corpid);
                } catch (Exception e) {
                    LOG.info("ReportTargetDataThread.saveCompanyTargetDate Exception, user=" + userEntity.getName() + "(userId：" + userEntity.getUserId() + "), corpid=" + corpid );
                }
            }
        }
    }
}
